package com.cq.hd.product.config;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cq.hd.common.constant.RedisKeyConstant;
import com.cq.hd.common.constant.WxConstant;
import com.cq.hd.common.enums.biz.WxMiniCodeShareTypeEnum;
import com.cq.hd.common.utils.FileUtils;
import com.cq.hd.common.utils.HttpUtils;
import com.cq.hd.common.utils.RedisUtil;
import com.cq.hd.common.utils.StringUtils;
import com.cq.hd.system.api.OssApi;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class WxConfig {

    private final static String IMG_NAME = "%s-%s.jpg";

    private final static String IMG_TYPE = "jpg";

    @Value("${zwx.appId}")
    private String appId;

    @Value("${zwx.appSecret}")
    private String appSecret;

    @Value("${swx.appId}")
    private String swxAppId;

    @Value("${swx.appSecret}")
    private String swxAppSecret;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private OssApi ossApi;

    public String getSwxApiToken() {
        String accessToken = redisUtil.get(String.format(RedisKeyConstant.MINI_TOKEN_KEY, swxAppId));
        if (StringUtils.isBlank(accessToken)) {
            String url = WxConstant.GET_TOKEN_API.replace("APP_ID", swxAppId).replace("SECRET", swxAppSecret);
            JSONObject jsonObject = JSON.parseObject(HttpUtil.get(url));
            accessToken = jsonObject.getString("access_token");
            Integer expiresIn = jsonObject.getInteger("expires_in");

            if (StringUtils.isBlank(accessToken)) {
                log.error("获取小程序token异常");
                return "";
            }

            redisUtil.set(String.format(RedisKeyConstant.MINI_TOKEN_KEY, swxAppId), accessToken, expiresIn, TimeUnit.SECONDS);

            return accessToken;
        }

        return accessToken;
    }


    public String getApiToken() {
        String accessToken = redisUtil.get(String.format(RedisKeyConstant.MINI_TOKEN_KEY, appId));
        if (StringUtils.isBlank(accessToken)) {
            String url = WxConstant.GET_TOKEN_API.replace("APP_ID", appId).replace("SECRET", appSecret);
            JSONObject jsonObject = JSON.parseObject(HttpUtil.get(url));
            accessToken = jsonObject.getString("access_token");
            Integer expiresIn = jsonObject.getInteger("expires_in");

            if (StringUtils.isBlank(accessToken)) {
                log.error("获取小程序token异常");
                return "";
            }

            redisUtil.set(String.format(RedisKeyConstant.MINI_TOKEN_KEY, appId), accessToken, expiresIn, TimeUnit.SECONDS);

            return accessToken;
        }

        return accessToken;
    }

    public String getWxMiniCode(String page, String params, Integer codeShareType, String key) {
        String imgName = String.format(IMG_NAME, codeShareType, key);
        String url = redisUtil.get(String.format(RedisKeyConstant.MINI_CODE_IMG_KEY, imgName));
        if (!StringUtils.isBlank(url)) {
            return url;
        }

        String accessToken = "";
        if (WxMiniCodeShareTypeEnum.INVITE_MERCHANT.getValue().equals(codeShareType)) {
            // 如果是生成邀请商户端小程序码，使用商户端的accessToken
            accessToken = getSwxApiToken();
        } else {
            // 如果是活动分享，邀请商家，邀请经纪人，使用主程序的accessToken
            accessToken = getApiToken();
        }

        if (StringUtils.isBlank(accessToken)) {
            log.error("生成小程序码失败，未获取到accessToken");
            return "";
        }

        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("page", page);
        // 最大32个可见字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~，其它字符请自行编码为合法字符（因不支持%，中文无法使用 urlencode 处理，请使用其他编码方式）
        paramsMap.put("scene", params);
        // 默认是true，检查page 是否存在，为 true 时 page 必须是已经发布的小程序存在的页面（否则报错）；为 false 时允许小程序未发布或者 page 不存在， 但page 有数量上限（60000个）请勿滥用
        paramsMap.put("check_path", false);
        // 正式版为 "release"，体验版为 "trial"，开发版为 "develop"。默认是正式版
        paramsMap.put("env_version", "release");

        try {
            HttpResponse httpResponse = HttpUtils.doPost("", WxConstant.GET_WX_CODE_UN_LIMIT_API.replace("ACCESS_TOKEN", accessToken),
                    new HashMap<>(), new HashMap<>(), JSON.toJSONString(paramsMap));
            InputStream inputStream = new ByteArrayInputStream(EntityUtils.toByteArray(httpResponse.getEntity()));
//            String imgUrl = ossConfig.uploadFile(inputStream, IMG_TYPE, "miniCode", imgName);
            MultipartFile multipartFile = FileUtils.createMultipartFile(inputStream, imgName);
            String imgUrl = ossApi.uploadFile(multipartFile, "miniCode", imgName).unpack();
            log.info("生成小程序码成功，imgUrl：{}", imgUrl);
            redisUtil.set(String.format(RedisKeyConstant.MINI_CODE_IMG_KEY, imgName), imgUrl, 24, TimeUnit.HOURS);
            return imgUrl;
        } catch (Exception e) {
            log.info("生成小程序码失败，params：{}", params, e);
        }

        return "";
    }

    public String generateShortLink(String pageUrl) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("page_url", pageUrl);

        try {
            String accessToken = getApiToken();
            HttpResponse httpResponse = HttpUtils.doPost("", WxConstant.GET_SHORT_LINK_API.replace("ACCESS_TOKEN", accessToken),
                    new HashMap<>(), new HashMap<>(), JSON.toJSONString(paramsMap));
            String result = EntityUtils.toString(httpResponse.getEntity());
            JSONObject jsonObject = JSON.parseObject(result);
            return jsonObject.getString("link");
        } catch (Exception e) {
            log.info("生成短链失败，pageUrl：{}", pageUrl, e);
        }
        return null;
    }

}
